/*
 * Copyright (c) 2009 John Pritchard, WTKX Project Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package wtkx.in;

import java.awt.Component;
import java.awt.Rectangle;

/**
 * Repainter to coalesce events.
 * 
 * @see Awtk
 * @author jdp
 */
public final class Animator
    extends java.lang.Thread
{
    public final static class Area 
        extends Rectangle
    {
        public Area(){
            super();
        }

        public boolean isEmpty(){
            return (0 == this.width && 0 == this.height);
        }
        public void add(Rectangle r){
            if (this.isEmpty()){
                this.x = r.x;
                this.y = r.y;
                this.width = r.width;
                this.height = r.height;
            }
            else
                super.add(r);
        }
        public void reset(){
            this.x = 0;
            this.y = 0;
            this.width = 0;
            this.height = 0;
        }
    }


    private final BackingStore graphics;

    private final Area area = new Area();


    Animator(Awtk awtk){
        super(wtkx.ui.Threads.Group(),"Animator");
        this.setDaemon(true);
        this.setPriority(MIN_PRIORITY);
        if (null != awtk){
            this.graphics = awtk.getBacking();
            if (null == this.graphics)
                throw new IllegalStateException();
        }
        else
            throw new IllegalArgumentException();
    }


    void repaint(int x, int y, int w, int h){
        Area a = this.area;
        synchronized(a){
            area.add(new Rectangle(x,y,w,h));
            a.notify();
        }
    }
    void repaint(Component component){
        Area a = this.area;
        synchronized(a){
            Rectangle r = component.getBounds();
            r.x = 0;
            r.y = 0;
            a.add(r);
            a.notify();
        }
    }


    public void run(){

        BackingStore graphics = this.graphics;

        Area a = this.area;
        int x = 0, y = 0, w = 0, h = 0;

        ani:
        while (true){
            try {
                synchronized(a){
                    if (a.isEmpty())
                        a.wait();

                    else {
                        x = a.x;
                        y = a.y;
                        w = a.width;
                        h = a.height;
                        a.reset();
                    }
                }

                long jump = 30L;
                rep:
                for (int ret = 0; ret < 3; ret++){
                    try {
                        graphics.reinit();
                        graphics.paint(x, y, w, h);

                        break rep;
                    }
                    catch (RepaintJump.Animating r){
                        jump = r.delay;
                        x = r.x;
                        y = r.y;
                        w = r.w;
                        h = r.h;
                        Thread.sleep(jump);
                        if (r.reset)
                            ret = 0;
                    }
                    catch (RepaintJump.Validating rep){
                        Thread.sleep(jump);
                        jump *= 2;
                    }
                }

            }
            catch (InterruptedException exc){
                return;
            }
            catch (Exception exc){
                exc.printStackTrace();
            }
        }
    }
}
